`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date:    10:24:56 03/31/2011 
// Design Name: 
// Module Name:    NbitPipelinedAdder 
// Project Name: 
// Target Devices: 
// Tool versions: 
// Description: 
//
// Dependencies: 
//
// Revision: 
// Revision 0.01 - File Created
// Additional Comments: 
//
//////////////////////////////////////////////////////////////////////////////////
module NbitPipelinedAdder #(parameter N=8)(
    input [N-1:0] x_in,
    input [N-1:0] y_in,
	 input c_in,
    output [N-1:0] s_out,
    output c_out,
	 input clock
    );
	 
	genvar i;
	 
	//all same size for convenience, will be optimized by synth tool
	//need a register between each fullAdder for inputs and outputs and carry
	reg [N-1:1] reg_input_a [0:N-2]; 
	reg [N-1:1] reg_input_b [0:N-2]; 
	reg [N-2:0] reg_output [0:N-2]; 
	reg reg_carry [0:N-2];
	
	wire fa_sum [N-1:0];
	wire fa_carry [N-1:0];
	
	fullAdder fa0(x_in[0], y_in[0], c_in, fa_sum[0], fa_carry[0]);
	 
	generate
		
		for(i=0;i<(N-1);i=i+1) begin: adders
			fullAdder FA (reg_input_a[i][i+1], reg_input_b[i][i+1], reg_carry[i], fa_sum[i+1], fa_carry[i+1]);
		end//for
	

		
		//Shift input registers
		always @(posedge clock) begin
			reg_input_a[0][N-1:1] <= x_in[N-1:1]; //Topmost level saves new inputs
			reg_input_b[0][N-1:1] <= y_in[N-1:1];
		end
			
		for(i=1; i<(N-1); i=i+1) begin: regShift
			always @(posedge clock) begin
				reg_input_a[i][N-1:i+1]<= reg_input_a[i-1][N-1:i+1];
				reg_input_b[i][N-1:i+1]<= reg_input_b[i-1][N-1:i+1];
			end
		end
		
		//Shift carry registers
		for(i=0; i<(N-1); i=i+1)begin:carryShift
			always @(posedge clock) begin
				reg_carry[i] <= fa_carry[i];
			end
		end
			
		//Shift output registers
		always @(posedge clock) begin
			reg_output[0][0] <= fa_sum[0];
		end
		for(i=1;i<(N-1);i=i+1) begin:outShift
			always @(posedge clock) begin
				reg_output[i][i:0] <= {fa_sum[i], reg_output[i-1][i-1:0]};
			end
		end
	endgenerate
	assign s_out = {fa_sum[N-1], reg_output[N-2][N-2:0]};
	assign c_out = fa_carry[N-1];
endmodule
